package com.zj.baseproxy.utils;

import com.zj.baseproxy.model.Page;
import org.springframework.core.ResolvableType;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author 19242
 */
public class ClassUtil {

    private static final Class<?>[] EMPTY_CLASS_ARR = new Class<?>[]{};

    /**
     * 获取某父类或接口上的泛型class
     *
     * @param clazz     当前类
     * @param targetClz 父类
     * @return 父类上的泛型数组
     */
    @NonNull
    public static Class<?>[] findGenericsClz(Class<?> clazz, Class<?> targetClz) {
        ResolvableType[] generics = findGenericsClz(ResolvableType.forClass(clazz), targetClz);
        if (Objects.isNull(generics)) {
            return EMPTY_CLASS_ARR;
        }
        Class<?>[] classes = new Class<?>[generics.length];
        for (int i = 0; i < generics.length; i++) {
            classes[i] = generics[i].resolve();
        }
        return classes;
    }

    /**
     * 寻找某父类或接口上的泛型
     *
     * @param resolvableType 解析的当前类
     * @param targetClz      父类
     * @return 父类上的泛型数组
     */
    @Nullable
    private static ResolvableType[] findGenericsClz(ResolvableType resolvableType, Class<?> targetClz) {
        if (Objects.isNull(targetClz)) {
            return null;
        }
        ResolvableType as = resolvableType.as(targetClz);
        if (as != ResolvableType.NONE) {
            // 获取泛型数组
            ResolvableType[] generics = as.getGenerics();
            if (generics.length == 0) {
                return null;
            }
            return generics;
        }
        return null;
    }

    /**
     * resolvableType的泛型里，targetClz上的泛型
     * 如（AA<BB<XXX>>，获取XXX.class）
     *
     * @param resolvableType 当前类
     * @param targetClz      获取这个类上的泛型
     * @return 只返回null和有数据
     */
    public static ResolvableType[] getGenericClass(ResolvableType resolvableType, Class<?> targetClz) {
        if (Objects.isNull(targetClz)) {
            return null;
        }
        Class<?> clazz = resolvableType.resolve();
        ResolvableType[] generics = resolvableType.getGenerics();
        // 获取泛型数组
        if (generics.length == 0) {
            return null;
        }
        if (clazz == targetClz) {
            return generics;
        }
        for (ResolvableType type : generics) {
            ResolvableType[] genericsClz = getGenericClass(type, targetClz);
            if (Objects.nonNull(genericsClz)) {
                return genericsClz;
            }
        }
        return null;
    }

    /**
     * 判断某类是否继承或实现某类
     *
     * @param childClass  子类
     * @param parentClass 父类
     * @return true 是
     */
    public static boolean isExtendsInterface(Class<?> childClass, Class<?> parentClass) {
        if (Objects.isNull(parentClass)) {
            return false;
        }
        return parentClass.isAssignableFrom(childClass);
    }

    /**
     * 判断是不是基本类型包装类
     *
     * @param clz 要校验的对象class
     * @return true 是
     */
    public static boolean isWrapClass(Class<?> clz) {
        try {
            return ((Class<?>) clz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 判断是不是基本类型
     * String、BigDecimal、long、int、double、float等
     *
     * @param clz 要校验的对象class
     * @return true 是
     */
    public static boolean isBaseType(Class<?> clz) {
        return String.class == clz || BigDecimal.class == clz
                || clz.isPrimitive() || ClassUtil.isWrapClass(clz);
    }

    /**
     * 如果是基础类型，返回包装类
     *
     * @param cls cls
     * @return 类
     */
    public static Class<?> getWrapClass(Class<?> cls) {
        if (cls.isPrimitive()) {
            if (cls == int.class) {
                return Integer.class;
            } else if (cls == byte.class) {
                return Byte.class;
            } else if (cls == short.class) {
                return Short.class;
            } else if (cls == long.class) {
                return Long.class;
            } else if (cls == float.class) {
                return Float.class;
            } else if (cls == double.class) {
                return Double.class;
            } else if (cls == char.class) {
                return Character.class;
            } else if (cls == boolean.class) {
                return Boolean.class;
            }
        }
        return cls;
    }

    /**
     * 转换对象o成cls类型返回
     * cls是基础类型则返回默认的
     *
     * @param o   要转换的对象
     * @param cls 要转换的类型
     * @return 转换后的类型
     */
    @SuppressWarnings("unchecked")
    public static <T> T cast(Object o, Class<T> cls) {
        // 基础类型
        if (cls.isPrimitive()) {
            if (cls == int.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Integer) ? 0 : o);
            } else if (cls == byte.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Byte) ? (byte) 0 : o);
            } else if (cls == short.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Short) ? (short) 0 : o);
            } else if (cls == long.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Long) ? 0L : o);
            } else if (cls == float.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Float) ? 0F : o);
            } else if (cls == double.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Double) ? 0D : o);
            } else if (cls == char.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Character) ? '\u0000' : o);
            } else if (cls == boolean.class) {
                return (T) (Objects.isNull(o) || !(o instanceof Boolean) ? false : o);
            }
        }
        // 类型不一致
        if (Objects.isNull(o) || o.getClass() != cls) {
            // 是集合，返回空集合
            if (List.class == cls) {
                return cls.cast(Collections.emptyList());
            } else if (Set.class == cls) {
                return cls.cast(Collections.emptySet());
            } else if (Map.class == cls) {
                return cls.cast(Collections.emptyMap());
            } else if (Page.class == cls) {
                return cls.cast(Page.setPageData());
            }
            return null;
        }
        return cls.cast(o);
    }
}
